
from .frame import Passer, Timer, ActEvent
from functools import partial


class Lib:
    def __init__(self):
        self.reflects = []
        self.routes = []

    def __lt__(self, name):
        assert isinstance(name, str)
        self.objs.append(name)

    def reflect(self, fire, state, *data):
        self.reflects.append((fire, state, data))

    def route(self, target, *data):
        self.routes.append((target, data))




class Brain:
    def __init__(self, lib):
        self.lib = lib
        self.think_timer = Timer(0.3)

        self.mode = "task"
        self.task_stack = ["静息"]
        self.mailbox = None
        self.solve_stack = Lock([])
        self.exchange_stack = []    # 交换栈，寄存流通对象
        self.return_to = []


    def mode_flip(self):
        if self.mode == "task":
            self.mode = "solve"
            self.task_stack = Lock(self.task_stack)
            self.solve_stack = self.solve_stack.get()
        elif self.mode == "solve":
            self.mode = "task"
            self.task_stack = self.task_stack.get()
            self.solve_stack = Lock(self.solve_stack)

    def reg_event(self, frame):
        frame.env_callback.append(self.perceive)
        self.think_timer.bind(partial(self.think_tick, frame))
        self.think_timer.reg_event(frame)

    def perceive(self, frame, e):
        print("感知：", e)
        self.mailbox = e.tag



    def think_tick(self, frame):
        def do_act(act):
            if act is None:
                return
            elif act.startswith("pack:"):
                s = act.partition("pack:")[2]
                print(' ' * 30 + "<pack>", s)
                self.exchange_stack.append(s)
            elif act.startswith("trace:"):
                if self.exchange_stack:
                    s = self.exchange_stack.pop()
                    print(' ' * 30 + "<trace>", s)
                    self.mailbox = s
            elif act.startswith("self:"):
                s = act.partition("self:")[2]
                print(' ' * 30 + "<self>", s)
                self.mailbox = s
            else:
                frame.post_event(ActEvent(act))


        if self.mode == "task":
            print(" "*20, "think", "" if self.mailbox is None else f"{{{self.mailbox}}}", self.task_stack, self.exchange_stack)
        else:
            print(" "*20, "think", self.solve_stack, self.exchange_stack)
        if self.mode == "task":
            if self.mailbox is None:
                return
            mail, self.mailbox = self.mailbox, None
            for rule in self.lib.reflects:
                fire, state, data = rule
                if state == self.task_stack[-1] and fire == mail:
                    if len(data) == 1 and data[0] == "ret":
                        print(' ' * 30 + "<ret>", data)
                        self.task_stack.pop()
                        if self.return_to.pop() == "solve":
                            self.mode_flip()
                        self.mailbox = "完成"
                    elif len(data) == 1 and data[0] == "ret-fail":
                        print(' ' * 30 + "<ret-fail>", data)
                        self.task_stack.pop()
                        if self.return_to.pop() == "solve":
                            self.mode_flip()
                        self.mailbox = "失败"
                    elif len(data) == 1:
                        act = data[0]
                        do_act(act)
                    elif len(data) == 2 and data[0] == "call":
                        print(' ' * 30 + "<call>", data)
                        fun = data[1]
                        self.task_stack.append(fun)
                        self.return_to.append("task")
                    elif len(data) == 2 and data[0] == "suggest":
                        print(' ' * 30 + "<suggest>", data)
                        fun = data[1]
                        self.mode_flip()
                        self.return_to.append("task")
                        self.solve_stack.append(fun)
                    elif len(data) == 2 and data[0] == "ret":
                        print(' ' * 30 + "<ret>", data)
                        self.task_stack.pop()
                        if self.return_to.pop() == "solve":
                            self.task_stack = Lock(self.task_stack)
                            self.solve_stack = self.solve_stack.get()
                        self.mailbox = "完成"
                        act = data[1]
                        do_act(act)
                    elif len(data) == 2 and data[0] == "ret-fail":
                        print(' ' * 30 + "<ret>", data)
                        self.task_stack.pop()
                        if self.return_to.pop() == "solve":
                            self.task_stack = Lock(self.task_stack)
                            self.solve_stack = self.solve_stack.get()
                        self.mailbox = "失败"
                        act = data[1]
                        do_act(act)
                    elif len(data) == 2:
                        print(' ' * 30 + "<move>", data)
                        next_state, act = data
                        do_act(act)
                        self.task_stack[-1] = next_state
                    elif len(data) == 3 and data[0] == "call":
                        print(' ' * 30 + "<call>", data)
                        fun = data[1]
                        self.task_stack.append(fun)
                        self.return_to.append("task")
                        act = data[2]
                        do_act(act)
                    break
        elif self.mode == "solve":
            if self.mailbox == "完成":
                print(' ' * 30 + "<achieve>", self.solve_stack[-1])
                self.solve_stack.pop()
                self.mailbox = "完成"
                if self.return_to.pop() == "task":
                    self.mode_flip()
                return
            # 目前的失败设计是反复循环搜索，如果始终无法解决，将会一直循环
            elif self.mailbox == "失败":
                i = next(i for i, (target, data) in enumerate(self.lib.routes) if target == self.solve_stack[-1])
                x = self.lib.routes.pop(i)
                self.lib.routes.append(x)
                self.mailbox = None
                return
            print("解决入口", self.solve_stack[-1], self.mailbox)
            for rule in self.lib.routes:
                target,  data = rule
                if target == self.solve_stack[-1]:
                    if len(data) == 1:
                        act = data
                        do_act(act)
                    elif len(data) == 3 and data[0] == "call":
                        print(' ' * 30 + "<call>", data)
                        fun = data[1]
                        self.mode_flip()
                        self.task_stack.append(fun)
                        self.return_to.append("solve")
                        act = data[2]
                        do_act(act)

                    break








class Lock:
    def __init__(self, x):
        self.__x = x

    def get(self):
        return self.__x
